/*
 * Copyright (C) 2009 Jorge Jimenez (jim@unizar.es)
 * Copyright (C) 2009 Diego Gutierrez (diegog@unizar.es)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must display the names 'Jorge Jimenez'
 *    and 'Diego Gutierrez' as 'Real-Time Rendering R&D' in the credits of the
 *    application, if such credits exist. The authors of this work must be
 *    notified via email (jim@unizar.es) in this case of redistribution.
 * 
 * 3. Neither the name of copyright holders nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software 
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include "stdafx.h"
#include <DXUT.h>
#include "RenderTarget.h"

using namespace DirectX;

const DXGI_SAMPLE_DESC RenderTarget::NO_MSAA = { 1, 0 };


RenderTarget::RenderTarget(ID3D11Device *device, int width, int height, DXGI_FORMAT format, const DXGI_SAMPLE_DESC &sampleDesc)
        : device(device), width(width), height(height) {
    HRESULT hr;

    D3D11_TEXTURE2D_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.Width = width;
    desc.Height = height;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.Format = format;
    desc.SampleDesc = sampleDesc;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    V(device->CreateTexture2D(&desc, NULL, &texture2D));

    D3D11_RENDER_TARGET_VIEW_DESC rtdesc;
    rtdesc.Format = desc.Format;
    if (sampleDesc.Count == 1) {
        rtdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
    } else {
        rtdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
    }
    rtdesc.Texture2D.MipSlice = 0;
    V(device->CreateRenderTargetView(texture2D, &rtdesc, &renderTargetView));

    D3D11_SHADER_RESOURCE_VIEW_DESC srdesc;
    srdesc.Format = desc.Format;
    if (sampleDesc.Count == 1) {
        srdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    } else {
        srdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
    }
    srdesc.Texture2D.MostDetailedMip = 0;
    srdesc.Texture2D.MipLevels = 1;
    V(device->CreateShaderResourceView(texture2D, &srdesc, &shaderResourceView));
}


RenderTarget::~RenderTarget() {
    SAFE_RELEASE(texture2D);
    SAFE_RELEASE(renderTargetView);
    SAFE_RELEASE(shaderResourceView);
}


void RenderTarget::setViewport(float minDepth, float maxDepth) const {
    D3D11_VIEWPORT viewport;
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = width;
    viewport.Height = height;
    viewport.MinDepth = minDepth;
    viewport.MaxDepth = maxDepth;
    context->RSSetViewports(1, &viewport);
}


const DXGI_SAMPLE_DESC DepthStencil::NO_MSAA = { 1, 0 };


DepthStencil::DepthStencil(ID3D11Device *device, int width, int height, DXGI_FORMAT texture2DFormat, const DXGI_FORMAT depthStencilViewFormat, DXGI_FORMAT shaderResourceViewFormat, const DXGI_SAMPLE_DESC &sampleDesc)
        : device(device), width(width), height(height) {
    HRESULT hr;

    D3D11_TEXTURE2D_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.Width = width;
    desc.Height = height;
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.Format = texture2DFormat;
    desc.SampleDesc = sampleDesc;
    desc.Usage = D3D11_USAGE_DEFAULT;
    if (sampleDesc.Count == 1) {
        desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    } else {
        desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    }
    V(device->CreateTexture2D(&desc, NULL, &texture2D));

    D3D11_DEPTH_STENCIL_VIEW_DESC dsdesc;
    dsdesc.Format = depthStencilViewFormat;
    if (sampleDesc.Count == 1) {
        dsdesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    } else {
        dsdesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
    }
    dsdesc.Texture2D.MipSlice = 0;
    V(device->CreateDepthStencilView(texture2D, &dsdesc, &depthStencilView));

    if (sampleDesc.Count == 1) {
        D3D11_SHADER_RESOURCE_VIEW_DESC srdesc;
        srdesc.Format = shaderResourceViewFormat;
        srdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        srdesc.Texture2D.MostDetailedMip = 0;
        srdesc.Texture2D.MipLevels = 1;
        V(device->CreateShaderResourceView(texture2D, &srdesc, &shaderResourceView));
    } else {
        shaderResourceView = NULL;
    }
}


DepthStencil::~DepthStencil() {
    SAFE_RELEASE(texture2D);
    SAFE_RELEASE(depthStencilView);
    SAFE_RELEASE(shaderResourceView);
}


void DepthStencil::setViewport(float minDepth, float maxDepth) const {
    D3D11_VIEWPORT viewport;
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = width;
    viewport.Height = height;
    viewport.MinDepth = minDepth;
    viewport.MaxDepth = maxDepth;
    context->RSSetViewports(1, &viewport);
}
